package talayaco.manager.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import talayaco.dao.AlimentoDAO;
import talayaco.dao.CorralDAO;
import talayaco.dao.impl.AlimentoDAOImpl;
import talayaco.dao.impl.CorralDAOImpl;
import talayaco.enums.TipoDietaEnum;
import talayaco.enums.TipoMovimientoEnum;
import talayaco.enums.UnidadAlimentoEnum;
import talayaco.interfaz.GestionProveedoresINT;
import talayaco.manager.GestionAlimentosMAN;
import talayaco.utils.DateUtils;
import talayaco.utils.MapToVo;
import talayaco.utils.StringUtils;
import talayaco.vo.ReporteAlimentoVO;
import talayaco.vo.ReporteHoteleriaVO;
import talayaco.vo.ReporteProporcionesVO;

public class GestionAlimentosMANimpl implements GestionAlimentosMAN {

	/**
	 * Alimento DAO
	 */
	private static AlimentoDAO alimentoDAO = new AlimentoDAOImpl();

	/**
	 * Corral DAO
	 */
	private static CorralDAO corralDAO = new CorralDAOImpl();

	/*
	 * (non-Javadoc)
	 * 
	 * @see talayaco.manager.GestionAlimentosMAN#getAlimentos()
	 */
	public List<String> getAlimentos() throws Exception {
		return alimentoDAO.getAlimentos();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * talayaco.manager.GestionAlimentosMAN#getUnidadByTipo(java.lang.String)
	 */
	public Map<String, String> getAlimentoByTipo(String tipo) throws Exception {
		Map<String, String> alimento = alimentoDAO.getAlimentoByTipo(tipo);
		String idUnidad = alimento.get("unidad");
		alimento.put("unidad", UnidadAlimentoEnum.getDescripcion(idUnidad));
		return alimento;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see talayaco.manager.GestionAlimentosMAN#insertIngreso(java.util.Map)
	 */
	public void insertIngreso(List<Map<String, String>> listado, Date unaFecha)
			throws Exception {

		Map<String, Object> datosIngreso;

		for (Map<String, String> ingresoListado : listado) {
			datosIngreso = new HashMap<String, Object>();

			datosIngreso.put("tipoMovimiento",
					TipoMovimientoEnum.INGRESO.getId());

			Map<String, String> datosAlimentos = getAlimentoByTipo(ingresoListado
					.get("tipoAlimento"));
			Long idAlimento = Long.parseLong(datosAlimentos.get("id"));
			datosIngreso.put("idAlimento", idAlimento.toString());
			datosIngreso.put("fecha", unaFecha);
			datosIngreso.put("cantidad", ingresoListado.get("cantidad"));
			datosIngreso.put("comprobante", ingresoListado.get("comprobante"));
			datosIngreso.put(
					"proveedor",
					GestionProveedoresINT.getProveedorByNombre(
							ingresoListado.get("proveedor").toString()).get(
							"id"));

			alimentoDAO.insertMovimiento(datosIngreso);

			// Actualizo el stock en cada uno de los egresos
			Map<String, String> datosUpdateCantidadAnimalesMap = new HashMap<String, String>();
			Long cantidadTotal = Long.parseLong(datosAlimentos.get("stock"))
					+ Long.parseLong(ingresoListado.get("cantidad"));
			datosUpdateCantidadAnimalesMap.put("cantidad",
					cantidadTotal.toString());
			datosUpdateCantidadAnimalesMap.put("id", idAlimento.toString());

			alimentoDAO.updateStockAlimento(datosUpdateCantidadAnimalesMap);
		}

	}

	public void deleteAlimentos(List<Map<String, String>> listado, Date unaFecha)
			throws Exception {

		Map<String, Object> datosEgreso;
		for (Map<String, String> egresoListado : listado) {
			datosEgreso = new HashMap<String, Object>();

			Map<String, String> datosAlimentos = getAlimentoByTipo(egresoListado
					.get("id"));
			Long idAlimento = Long.parseLong(datosAlimentos.get("id"));
			datosEgreso.put("idAlimento", idAlimento.toString());
			datosEgreso.put("fecha", unaFecha);
			datosEgreso.put("tipoMovimiento",
					egresoListado.get("tipoMovimiento"));
			datosEgreso.put("cantidad", egresoListado.get("cantidad"));
			alimentoDAO.insertMovimiento(datosEgreso);

			// Actualizo el stock en cada uno de los egresos
			Map<String, String> datosUpdateCantidadAnimalesMap = new HashMap<String, String>();
			Long cantidadTotal = Long.parseLong(datosAlimentos.get("stock"))
					- Long.parseLong(egresoListado.get("cantidad"));
			datosUpdateCantidadAnimalesMap.put("cantidad",
					cantidadTotal.toString());
			datosUpdateCantidadAnimalesMap.put("id", idAlimento.toString());

			alimentoDAO.updateStockAlimento(datosUpdateCantidadAnimalesMap);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see talayaco.manager.GestionAlimentosMAN#nuevoAlimento(java.lang.String,
	 * java.lang.String)
	 */
	public void nuevoAlimento(String nombre, String unidadMedida)
			throws Exception {
		Map<String, String> nuevoAlimento = new HashMap<String, String>();
		nuevoAlimento.put("nombre", nombre);
		nuevoAlimento.put("unidadMedida", unidadMedida);
		alimentoDAO.insertAlimento(nuevoAlimento);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see talayaco.manager.GestionAlimentosMAN#insertDieta(java.util.List,
	 * java.util.Date, talayaco.enums.TipoDietaEnum)
	 */
	public void insertDieta(List<Map<String, String>> datosProporciones,
			Date fechaDesde, String tipoDieta) throws Exception {

		Map<String, Object> datosDieta = new HashMap<String, Object>();
		datosDieta.put("fechaDesde", fechaDesde);
		datosDieta.put("tipo", tipoDieta);

		Date fechaAyer = new Date(fechaDesde.getTime()
				- (1L * 24L * 60L * 60L * 1000L));
		datosDieta.put("fechaHasta", fechaAyer);
		alimentoDAO.updateFechaHastaDieta(datosDieta);

		alimentoDAO.insertDieta(datosDieta);

		Long idDieta = alimentoDAO.getIdDieta(datosDieta);

		Map<String, String> datosIngresoProporcion;
		for (Map<String, String> proporcion : datosProporciones) {
			datosIngresoProporcion = new HashMap<String, String>();
			Map<String, String> datosAlimentos = getAlimentoByTipo(proporcion
					.get("id"));
			Long idAlimento = Long.parseLong(datosAlimentos.get("id"));
			datosIngresoProporcion.put("idAlimento", idAlimento.toString());
			datosIngresoProporcion
					.put("cantidad", proporcion.get("proporcion"));
			datosIngresoProporcion.put("idDieta", idDieta.toString());
			alimentoDAO.insertProporcion(datosIngresoProporcion);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * talayaco.manager.GestionAlimentosMAN#existeAlimento(java.lang.String)
	 */
	public Boolean existeAlimento(String nombre) throws Exception {
		String existe = new String();
		existe = (String) alimentoDAO.existeAlimento(nombre);

		if (existe.equals("1"))
			return true;
		else
			return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * talayaco.manager.GestionAlimentosMAN#validarStockAlimento(java.lang.String
	 * , java.lang.String)
	 */
	public Integer validarStockAlimento(String nombreAlimento, String cantidad)
			throws Exception {
		Long existenciaReal = alimentoDAO
				.cantidadAlimentosByNombre(nombreAlimento);

		if (existenciaReal >= Long.parseLong(cantidad)) {
			return -1;
		} else {
			return Integer.parseInt(existenciaReal.toString());
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see talayaco.manager.GestionAlimentosMAN#getAlimentosCantidad()
	 */
	public List<ReporteAlimentoVO> getAlimentosCantidad() throws Exception {

		// Busco las fechas para cada tipo de dieta
		List<String> tiposDietas = new ArrayList<String>();
		tiposDietas.add(TipoDietaEnum.A.getId());
		tiposDietas.add(TipoDietaEnum.E.getId());
		tiposDietas.add(TipoDietaEnum.H.getId());
		tiposDietas.add(TipoDietaEnum.R.getId());

		Map<String, Double> cantidadTotalAlimentos = new HashMap<String, Double>();

		List<Map<String, String>> fechas = new ArrayList<Map<String, String>>();
		for (String dieta : tiposDietas) {

			fechas = getFechasDietas(dieta);
			if (fechas != null) {
				String idUltimaFechaDieta = fechas.get(fechas.size() - 1).get(
						"id");

				Map<String, String> datosProporciones = new HashMap<String, String>();
				List<ReporteProporcionesVO> reporteProporcionesVO = getProporcionesDieta(
						idUltimaFechaDieta, dieta, datosProporciones);

				Map<String, Object> tipoDieta = new HashMap<String, Object>();
				tipoDieta.put("tipo", dieta);
				Double cantidadMezclaDia = alimentoDAO
						.getCantidadConsumidaPorCorralUltimoDia(tipoDieta);

				corregirSinCantidadReal(reporteProporcionesVO);

				for (ReporteProporcionesVO proporcionesAlimento : reporteProporcionesVO) {
					Double cantidadDiariaAlimento = Double
							.valueOf(proporcionesAlimento.getProporcionReal())
							* cantidadMezclaDia;

					if (cantidadTotalAlimentos.get(proporcionesAlimento
							.getAlimento()) == null) {
						cantidadTotalAlimentos.put(
								proporcionesAlimento.getAlimento(),
								cantidadDiariaAlimento);
					} else {
						cantidadTotalAlimentos.put(
								proporcionesAlimento.getAlimento(),
								cantidadTotalAlimentos.get(proporcionesAlimento
										.getAlimento())
										+ cantidadDiariaAlimento);
					}
				}
			}
		}

		List<Map<String, String>> listaAlimentos = alimentoDAO
				.getAlimentosCantidad();
		List<ReporteAlimentoVO> alimentoCantidadVO = new ArrayList<ReporteAlimentoVO>();
		ReporteAlimentoVO reporteAlimentoVO = new ReporteAlimentoVO();
		for (Map<String, String> alimento : listaAlimentos) {
			reporteAlimentoVO = MapToVo.mapToAlimentoVO(alimento);

			Double cantidadDiariaAlimento = cantidadTotalAlimentos.get(alimento
					.get("nombre"));
			if (cantidadDiariaAlimento == null) {
				reporteAlimentoVO.setConsumoDiario("No se usa actualmente");
				reporteAlimentoVO.setDiasRestantes("No se usa actualmente");
			} else {
				Double cantidadEstimadaDias = Double.valueOf(reporteAlimentoVO
						.getStock()) / cantidadDiariaAlimento;

				reporteAlimentoVO.setConsumoDiario(String
						.valueOf(cantidadDiariaAlimento.longValue()));

				reporteAlimentoVO.setDiasRestantes(String
						.valueOf(cantidadEstimadaDias.longValue()));
			}

			alimentoCantidadVO.add(reporteAlimentoVO);
		}
		return alimentoCantidadVO;
	}

	private void corregirSinCantidadReal(
			List<ReporteProporcionesVO> reporteProporcionesVO) {
		for (ReporteProporcionesVO proporcionesAlimento : reporteProporcionesVO) {
			if (proporcionesAlimento.getProporcionReal().equals("")) {
				proporcionesAlimento.setProporcionReal("0");

			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * talayaco.manager.GestionAlimentosMAN#getFechasDietas(java.lang.String)
	 */
	public List<Map<String, String>> getFechasDietas(String tipoDieta)
			throws Exception {
		List<Map<String, String>> datos = new ArrayList<Map<String, String>>();

		Date fecha = corralDAO.getFechaUltimaModificacionCorral(tipoDieta);

		List<Map<String, String>> fechasDietas = alimentoDAO.getFechasDietas(
				tipoDieta, fecha);

		for (Map<String, String> datosDieta : fechasDietas) {
			if (!StringUtils.isNullOrBlank(datosDieta.get("fechaDesde"))) {
				datosDieta.put("fechaDesde", DateUtils
						.getFechaFormateada(datosDieta.get("fechaDesde")));
			}

			if (!StringUtils.isNullOrBlank(datosDieta.get("fechaHasta"))) {
				datosDieta.put("fechaHasta", DateUtils
						.getFechaFormateada(datosDieta.get("fechaHasta")));
			}
			datos.add(datosDieta);
		}

		if (fecha != null && !fechasDietas.isEmpty())
			fechasDietas.get(0).put("fechaDesde",
					DateUtils.format(fecha, DateUtils.FORMAT_DDMMYYYY));
		return datos;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * talayaco.manager.GestionAlimentosMAN#getProporcionesDieta(java.lang.String
	 * , java.lang.String, java.util.Map)
	 */
	public List<ReporteProporcionesVO> getProporcionesDieta(String id,
			String tipoDieta, Map<String, String> params) throws Exception {
		List<ReporteProporcionesVO> reporteProporcionesVO = new ArrayList<ReporteProporcionesVO>();
		List<Map<String, String>> datosProporcionesDietaTeorica = alimentoDAO
				.getProporcionesDieta(id);
		Map<String, Object> fechaDieta = alimentoDAO.getFechasByDietaId(id);
		fechaDieta.put("tipo", tipoDieta);
		Double cantidadDouble = alimentoDAO
				.getCantidadConsumidaPorCorral(fechaDieta);
		if (null != cantidadDouble) {
			BigDecimal cantidadesConsumidasPorCorral = new BigDecimal(
					cantidadDouble).setScale(2, BigDecimal.ROUND_HALF_UP);
			params.put("cantidadMezclaTotal",
					cantidadesConsumidasPorCorral.toString());
			String tipoMovimiento = TipoMovimientoEnum
					.getTipoMovimiento(tipoDieta);
			fechaDieta.put("tipo", tipoMovimiento);
			List<Map<String, String>> movimientos = alimentoDAO
					.getCantidadMovimientos(fechaDieta);

			reporteProporcionesVO = MapToVo.toReportePropocionesVO(
					datosProporcionesDietaTeorica, movimientos,
					cantidadesConsumidasPorCorral, params);
		}
		return reporteProporcionesVO;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * talayaco.manager.GestionAlimentosMAN#getReporteHoteleriaVO(java.lang.
	 * String, java.util.Date, java.util.Date)
	 */
	public List<ReporteHoteleriaVO> getReporteHoteleriaVO(String caravana,
			Date fechaDesde, Date fechaHasta) throws Exception {

		List<Map<String, Object>> cantidadesMap = alimentoDAO
				.getCantidadConsumidas(fechaDesde, fechaHasta);

		List<ReporteHoteleriaVO> listaReporteHoteleriaVO = new ArrayList<ReporteHoteleriaVO>();
		List<String> nombresAlimentos = alimentoDAO.getAlimentos();
		for (String nombreAlimento : nombresAlimentos) {
			ReporteHoteleriaVO reporteHoteleriaVO = new ReporteHoteleriaVO();
			reporteHoteleriaVO.setAlimento(nombreAlimento);
			reporteHoteleriaVO.setCantidad(new BigDecimal(0));
			listaReporteHoteleriaVO.add(reporteHoteleriaVO);
		}

		for (Map<String, Object> cantidadMap : cantidadesMap) {
			List<Map<String, String>> datosDieta = alimentoDAO
					.getDietasByFecha((Date) cantidadMap.get("fecha"));

			BigDecimal cantidadConsumidaPorAnimal = new BigDecimal(cantidadMap
					.get("proporcion").toString()).setScale(2,
					BigDecimal.ROUND_HALF_UP);

			for (Map<String, String> dieta : datosDieta) {
				BigDecimal cantidadAlimentoConsumida = cantidadConsumidaPorAnimal
						.multiply(new BigDecimal(dieta.get("cantidadTotal")
								.toString()));
				for (ReporteHoteleriaVO reporte : listaReporteHoteleriaVO) {
					if (reporte.getAlimento().equals(
							dieta.get("nombre").toString())) {
						reporte.setCantidad(cantidadAlimentoConsumida.add(
								reporte.getCantidad()).setScale(2,
								BigDecimal.ROUND_HALF_UP));
					}
				}
			}
		}

		return listaReporteHoteleriaVO;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * talayaco.manager.GestionAlimentosMAN#getReporteHoteleriaVO(java.lang.
	 * String, java.util.Date, java.util.Date)
	 */
	public List<ReporteHoteleriaVO> getReporteHoteleriaClienteVO(
			String cliente, Date fechaDesde, Date fechaHasta) throws Exception {

		List<Map<String, Object>> cantidadesMap = alimentoDAO
				.getCantidadConsumidas(fechaDesde, fechaHasta);

		List<ReporteHoteleriaVO> listaReporteHoteleriaVO = new ArrayList<ReporteHoteleriaVO>();
		List<String> nombresAlimentos = alimentoDAO.getAlimentos();
		for (String nombreAlimento : nombresAlimentos) {
			ReporteHoteleriaVO reporteHoteleriaVO = new ReporteHoteleriaVO();
			reporteHoteleriaVO.setAlimento(nombreAlimento);
			reporteHoteleriaVO.setCantidad(new BigDecimal(0));
			listaReporteHoteleriaVO.add(reporteHoteleriaVO);
		}

		for (Map<String, Object> cantidadMap : cantidadesMap) {
			List<Map<String, String>> datosDieta = alimentoDAO
					.getDietasByFecha((Date) cantidadMap.get("fecha"));

			BigDecimal cantidadConsumidaPorAnimal = new BigDecimal(cantidadMap
					.get("proporcion").toString()).setScale(2,
					BigDecimal.ROUND_HALF_UP);

			for (Map<String, String> dieta : datosDieta) {
				BigDecimal cantidadAlimentoConsumida = cantidadConsumidaPorAnimal
						.multiply(new BigDecimal(dieta.get("cantidadTotal")
								.toString()));
				for (ReporteHoteleriaVO reporte : listaReporteHoteleriaVO) {
					if (reporte.getAlimento().equals(
							dieta.get("nombre").toString())) {
						reporte.setCantidad(cantidadAlimentoConsumida.add(
								reporte.getCantidad()).setScale(2,
								BigDecimal.ROUND_HALF_UP));
					}
				}
			}
		}

		return listaReporteHoteleriaVO;
	}

}
